package com.rfid.mqtt;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.rfid.a252robot.App;
import com.rfid.a252robot.admin.bean.Address;
import com.rfid.a252robot.bean.Log;
import com.rfid.a252robot.event.MapInfoEvent;
import com.rfid.a252robot.event.QrEvent;
import com.rfid.a252robot.event.RobotTaskEvent;
import com.rfid.a252robot.event.StopEvent;
import com.rfid.a252robot.event.ZhaoHuiEvent;
import com.rfid.common.log.LogUtils;
import com.rfid.manager.LogUploadManager;
import com.rfid.mqtt.bean.LocationRespon;
import com.rfid.mqtt.bean.QrRespon;
import com.rfid.mqtt.bean.MapInfo;
import com.rfid.mqtt.bean.QueryTaskRespon;
import com.rfid.mqtt.bean.StatusRespon;
import com.rfid.mqtt.bean.TaskInfo;
import com.rfid.mqtt.bean.TaskInfoRespon;
import com.rfid.mqtt.bean.TaskRespon;
import com.rfid.mqtt.bean.VoiceControlRespon;
import com.rfid.mqtt.bean.ZhaoHui;
import com.rfid.util.ACache;
import com.spectre.generate.ConfigManager;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.List;
import java.util.UUID;


public enum  MqttManager implements MqttCallback, IMqttActionListener {

    INSTANCE;

    String deviceId = "GINLITXR-1LXXXXXXXXXGNL03S2105000454";
    String cloudToRoBot;
    String robotToCloud = "cloud/events/commands";

    private String HOST = "tcp://4o37q36826.goho.co:24875";
    private String USERNAME = "admin";//用户名
    private String PASSWORD = "public";//密码

    public static final String TAG = "MQTT";

    private MqttAndroidClient mqttAndroidClient;
    private MqttConnectOptions mMqttConnectOptions;
    public String CLIENTID = UUID.randomUUID().toString();

    private TaskInfo mTaskInfo;
    private LoopTask mLoopTask;

    //12 上报机器人状态 休闲忙碌
    int CMD_UPLOAD_STATUS = 90015;
    //13 召唤任务
    int CMD_ZHAOHUAN = 90010;

    boolean isZhaohui = false;

    boolean isCancel = true;
    Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (!isMqttConnect()) {
                doClientConnection();
                mHandler.sendEmptyMessageDelayed(1,10000);
                return false;
            }
            queryStatus();
            mHandler.sendEmptyMessageDelayed(1,30000);
            return false;
        }
    });


    public void init(Context context) {
        LogUtils.v(TAG,"MqttService onCreate");
        String host = ConfigManager.INSTANCE.getGlobalConfig().getRobotUrl();
        deviceId = ConfigManager.INSTANCE.getGlobalConfig().getDeviceId();
//        deviceId = "PATROLCPAT-CM-B33XXXPAT13S2320000004";
        cloudToRoBot = String.format("cloud/{%s}/events/commands",deviceId);
        LogUtils.v(TAG,"mqtt url = " + host);
        if(mqttAndroidClient != null) {
            mqttAndroidClient.close();
        }
        mqttAndroidClient = new MqttAndroidClient(context, host, CLIENTID);
        mqttAndroidClient.setCallback(this); //设置监听订阅消息的回调
        mMqttConnectOptions = new MqttConnectOptions();
        mMqttConnectOptions.setCleanSession(true); //设置是否清除缓存
        mMqttConnectOptions.setConnectionTimeout(3); //设置超时时间，单位：秒
        mMqttConnectOptions.setKeepAliveInterval(20); //设置心跳包发送间隔，单位：秒
        mMqttConnectOptions.setUserName(USERNAME); //设置用户名
        mMqttConnectOptions.setPassword(PASSWORD.toCharArray()); //设置密码
        doClientConnection();
        mHandler.removeMessages(1);
        mHandler.sendEmptyMessageDelayed(1,10000);
    }

    private void doClientConnection() {
        LogUtils.v(TAG,"MQTT doClientConnection");
        if (!mqttAndroidClient.isConnected() && isConnectIsNomarl()) {
            try {
                mqttAndroidClient.connect(mMqttConnectOptions, null, this);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean isMqttConnect() {
        return mqttAndroidClient != null&&mqttAndroidClient.isConnected();
    }

    /**
     * 判断网络是否连接
     */
    private boolean isConnectIsNomarl() {
        ConnectivityManager connectivityManager = (ConnectivityManager) App.getApp().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()) {
            String name = info.getTypeName();
            LogUtils.v(TAG,"MQTT, 当前网络名称：" + name);
            return true;
        } else {
            LogUtils.v(TAG,"MQTT,没有可用网络");
            /*没有可用网络的时候，延迟3秒再尝试重连*/
//            new Handler().postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    doClientConnection();
//                }
//            }, 3000);
            return false;
        }
    }

    @Override
    public void connectionLost(Throwable cause) {
        if (cause != null) {
            LogUtils.e(TAG,"connectionLost = " + cause);
            doClientConnection();
        } else {
            LogUtils.v("connectionLost");
        }
    }

    public TaskInfo getCurrentTask() {
        return mTaskInfo;
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        try {
            String msg = new String(message.getPayload());
            Gson gson = new Gson();
            JsonParser parser = new JsonParser();
            JsonObject jo = parser.parse(msg).getAsJsonObject();
            int cmd = jo.get("cmd").getAsInt();
            if (cmd != 90007 && cmd != 90008) {
                LogUtils.v(TAG, "receive = " + msg);
            }
            if (cmd == 90001) {
                MapInfo mapInfo = gson.fromJson(msg, MapInfo.class);
                EventBus.getDefault().post(new MapInfoEvent(mapInfo));
            } else if (cmd == 90002) {
                //2.机器人向阿法迪云服务发送发起任务的接口
                TaskRespon taskRespon = gson.fromJson(msg, TaskRespon.class);
                if (taskRespon.getData().getCode() == 4002) {
                    queryStatus();
                }
            } else if (cmd == 90003) {
                TaskInfoRespon taskInfoRespon = gson.fromJson(msg, TaskInfoRespon.class);
                String taskInstanceId = taskInfoRespon.getData().getParams().getTaskInstanceId();
                TaskInfo taskInfo = new TaskInfo();
                taskInfo.setTaskInstanceId(taskInstanceId);
                taskInfo.setTaskName( taskInfoRespon.getData().getParams().getTaskName());
                taskInfo.setStatus(taskInfoRespon.getData().getParams().getStatus());
                EventBus.getDefault().post(new RobotTaskEvent(taskInfo));
            } else if (cmd == 90007) {
                StatusRespon statusRespon = gson.fromJson(msg,StatusRespon.class);
            }  else if (cmd == 90008) {
                //8.阿法迪云服务向机器人推送位置信息
                LocationRespon locationRespon = gson.fromJson(msg,LocationRespon.class);
            } else if (cmd == 90013) {

            } else if (cmd == 90014) {
                LogUtils.v(TAG,msg);
                QrRespon qrRespon = gson.fromJson(msg, QrRespon.class);
                if (qrRespon.getData() == null) {
                    return;
                }
                int status = qrRespon.getData().getStatus();
                if (status == 3) {
                    EventBus.getDefault().post(new QrEvent("",false));
                    return;
                }
                if (status != 4) {
                    return;
                }
                if (qrRespon.getData().getData() == null) {
                    return;
                }
                if (qrRespon.getData().getData().size() == 0) {
                    return;
                }
                String qr = qrRespon.getData().getData().get(0).getData();
                EventBus.getDefault().post(new QrEvent(qr,true));
            } else if (cmd == 90016) {
                LogUtils.v("receve 900016");
                QueryTaskRespon qt = gson.fromJson(msg,QueryTaskRespon.class);
                if (qt.getData().getData() == null) {
                    return;
                }
                TaskInfo taskInfo = new TaskInfo();
                taskInfo.setTaskInstanceId(qt.getData().getData().getTaskInstanceId());
                taskInfo.setTaskName(qt.getData().getData().getTaskName());
                taskInfo.setStatus(qt.getData().getData().getStatus());
                mTaskInfo = taskInfo;
                EventBus.getDefault().post(new RobotTaskEvent(taskInfo));
            } else if (cmd == 90017) {
                VoiceControlRespon vc = gson.fromJson(msg,VoiceControlRespon.class);
                List<VoiceControlRespon.DataBean.AnswerBean.TtsBean> tts = vc.getData().getAnswer().getTts();
                for (VoiceControlRespon.DataBean.AnswerBean.TtsBean bean : tts) {
                    if ("Stop".equals(bean.getAction().getParam().getIntent())) {
                        EventBus.getDefault().post(new StopEvent());
                        break;
                    }
                }

            } else if (cmd == 90005) {
//                if (!isCancel) {
//                    startMoveTask(false);
//                }
            } else if (cmd == CMD_ZHAOHUAN) {
                isZhaohui = true;
                EventBus.getDefault().post(new ZhaoHuiEvent(isZhaohui));
                ZhaoHui zh = gson.fromJson(msg, ZhaoHui.class);
                cancelTask(true);
                zhaohui(zh);
                Log log = new Log();
                log.setOpType("机器人召回");
                LogUploadManager.INSTANCE.upload(log);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.v(e.getMessage());
        }
    }

    public void resetTaskInfo() {
        mTaskInfo = null;
    }

    public void zhaohui(ZhaoHui zh) {
        List<Address> addresses = ACache.get().getAsAddresses("routes");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(Address ad : addresses) {
            if (ad.getPointName().equals(zh.getData().getBizPointName())) {
                startMoveTask(ad.getBizPointId());
            }
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        try {
            LogUtils.v(TAG,"deliveryComplete = " + new String(token.getMessage().getPayload()));
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSuccess(IMqttToken asyncActionToken) {
        LogUtils.v(TAG,"MQTT,连接成功");
        try {
            LogUtils.v(TAG,"register " + cloudToRoBot);
            String[] subs = new String[]{cloudToRoBot};
            mqttAndroidClient.subscribe(subs, new int[]{subs.length});
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
        LogUtils.v(TAG,"MQTT,连接失败");
        if (exception != null) {
            exception.printStackTrace();
        }
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                doClientConnection();
            }
        }, 3000);//连接失败，重连（可关闭服务器进行模拟）
    }

    public void scanQr() {
        JsonObject jo = buildHead(90014);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("opId",UUID.randomUUID().toString());
        send(jo.toString());
    }

    public boolean startMoveTask(String ...bizPointId){
        JsonObject jo = buildHead(90002);
        JsonObject data = jo.get("data").getAsJsonObject();
        JsonArray array = new JsonArray();
        for (String p : bizPointId) {
            array.add(p);
        }
//        data.addProperty("bizPointId",bizPointId);
        data.add("bizPointId",array);
        String json = jo.toString();
        return send(json);
    }

    public boolean startMoveTask(boolean user){
        LogUtils.v("startMoveTask user = " + user);
//        if (mLoopTask == null && !loop) {
//            LogUtils.v("resume startTask meet cancel!");
//            return false;
//        }
        hasMove = true;
        if (user) {
            isCancel = false;
            isZhaohui = false;
            EventBus.getDefault().post(new ZhaoHuiEvent(isZhaohui));
        } else if (isCancel) {
            LogUtils.v("prevent startMoveTask,isCancel!");
            return false;
        } else if (isZhaohui) {
            LogUtils.v("prevent startMoveTask,isZhaohui!");
            return false;
        }
//        if (mTaskInfo != null) {
//            int status = mTaskInfo.getStatus();
//            if (status==6) {
//                cancelTask(false);
//                try {
//                    Thread.sleep(500);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
        if (mLoopTask == null) {
            mLoopTask = new LoopTask(this);
        }
        String bizPointId = ACache.get().getAsString("current");
        List<Address> ss = ACache.get().getAsAddresses("selectRoutes");
        LogUtils.v(ss);
        if (ss.size() == 0) {
            LogUtils.v("selectRoutes is not set,return!");
            return false;
        }
        String ps[] = new String[ss.size()];
        for (int i=0;i<ss.size();i++) {
            ps[i] = ss.get(i).getBizPointId();
        }
        if (TextUtils.isEmpty(bizPointId)) {
            bizPointId = ps[0];
        } else {
            boolean found = false;
            for (String point:ps) {
                if (point.equals(bizPointId)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                bizPointId = ps[0];
            }
        }
        ACache.get().put("current",bizPointId);
        JsonObject jo = buildHead(90002);
        JsonObject data = jo.get("data").getAsJsonObject();
        JsonArray array = new JsonArray();
        array.add(bizPointId);
        data.add("bizPointId",array);
        String json = jo.toString();
        return send(json);
    }
    boolean hasMove = false;
    public boolean pauseRobot() {
        if (isZhaohui) {
            return false;
        }
        String taskInstanceId = null;
//        if (mTaskInfo != null) {
//            taskInstanceId = mTaskInfo.getTaskInstanceId();
//        }
//        if (TextUtils.isEmpty(taskInstanceId)) {
//            return false;
//        }
        //取消结束的情况下返回，暂停也是取消结束
        if (mTaskInfo != null && mTaskInfo.getStatus() == 5) {
            return false;
        }
        cancelTask(false);
        if (hasMove) {
            Log log = new Log();
            log.setOpType("机器人暂停");
            LogUploadManager.INSTANCE.upload(log);
        }
        hasMove = false;
        uploadStatus(false);
        if (true)
            return false;
        LogUtils.v("pauseRobot");
        JsonObject jo = buildHead(90004);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("taskInstanceId",taskInstanceId);
        String json = jo.toString();
        return send(json);
    }

    public boolean cancelTask(boolean user) {
        LogUtils.v("cancelTask");
        if (user) {
            isCancel = true;
        }
        if (mLoopTask != null) {
            mLoopTask.destroy();
            mLoopTask = null;
        }
        if (mTaskInfo == null) {
            LogUtils.v("getCurrent Task fail,return!");
            return false;
        }
        String taskInstanceId = mTaskInfo.getTaskInstanceId();
        JsonObject jo = buildHead(90005);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("taskInstanceId",taskInstanceId);
        String json = jo.toString();
        return send(json);
    }

    public boolean resumeRobot() {
        if (mTaskInfo == null) {
            return false;
        }
        if (isZhaohui) {
            return false;
        }
        Log log = new Log();
        log.setOpType("机器人运行");
        LogUploadManager.INSTANCE.upload(log);
//        if (mTaskInfo.getStatus() == 6) {
            startMoveTask(false);
//        }
        if (true)
            return false;
        String taskInstanceId = mTaskInfo.getTaskInstanceId();
        JsonObject jo = buildHead(90006);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("taskInstanceId",taskInstanceId);
        String json = jo.toString();
        return send(json);
    }

    public boolean getMapInfo() {
        JsonObject jo = buildHead(90001);
        JsonObject data = jo.get("data").getAsJsonObject();
        String json = jo.toString();
        return send(json);
    }

    public boolean queryStatus() {
        JsonObject jo = buildHead(90016);
        String json = jo.toString();
        return send(json);
    }

    public boolean uploadStatus(boolean free) {
        JsonObject jo = buildHead(CMD_UPLOAD_STATUS);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("status",free?0:1);
        return send(jo.toString());
    }

    private boolean send(String json) {
//        if (!isMqttConnect()) {
//            doClientConnection();
//        }
        MqttMessage msg = new MqttMessage();
        msg.setPayload(json.getBytes());
        LogUtils.v("send " + json);
        try {
            mqttAndroidClient.publish(robotToCloud, msg);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.v("send error = " + e.getMessage());
        }
        return false;
    }

    public boolean sendVoice(String voice) {
        JsonObject jo = buildHead(90013);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("opId",UUID.randomUUID().toString());
        data.addProperty("txt",voice);
        return send(jo.toString());
    }

    public boolean sendCharge(String mapCode,String pointName) {
//        if (mTaskInfo != null) {
//            cancelTask(false);
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        JsonObject jo = buildHead(90009);
        JsonObject data = jo.get("data").getAsJsonObject();
        data.addProperty("mapCode",mapCode);
        data.addProperty("pointName",pointName);
        return send(jo.toString());
    }

    private JsonObject buildHead(int cmd) {
        JsonObject jo = new JsonObject();
        jo.addProperty("cmd",cmd);
        JsonObject data = new JsonObject();
        jo.add("data",data);
        data.addProperty("robot_device_id",deviceId);
        return jo;
    }

    public void release() {
        try {
            String[] subs = new String[]{cloudToRoBot};
            mqttAndroidClient.unsubscribe(subs);
            mqttAndroidClient.unregisterResources();
            mqttAndroidClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class LoopTask {

        MqttManager mqttManager;
        Handler handler = new Handler(Looper.getMainLooper());
        boolean loop;
        public LoopTask(MqttManager manager) {
            mqttManager = manager;
            EventBus.getDefault().register(this);
        }

        public void destroy() {
            mqttManager = null;
            handler.removeMessages(0);
            EventBus.getDefault().unregister(this);
        }

        @Subscribe(threadMode = ThreadMode.MAIN)
        public void onTaskEvent(RobotTaskEvent event) {
            TaskInfo taskInfo = event.getTaskInfo();
            if (taskInfo != null) {
                int status = taskInfo.getStatus();
                if (status == 4) {
                    String point = ACache.get().getAsString("current");
                    String newPoint = null;
                    List<Address> ss = ACache.get().getAsAddresses("selectRoutes");
                    for (int i=0;i<ss.size();i++) {
                        if (ss.get(i).getBizPointId().equals(point)) {
                            if (i == ss.size() - 1) {
                                i = 0;
                            } else {
                                i++;
                            }
                            newPoint = ss.get(i).getBizPointId();
                            break;
                        }
                    }
                    if (TextUtils.isEmpty(newPoint)) {
                        newPoint = ss.get(0).getBizPointId();
                    }
                    handler.removeMessages(0);
                    String finalPoint = newPoint;
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (mqttManager == null) {
                                return;
                            }
                            ACache.get().put("current", finalPoint);
                            mqttManager.startMoveTask(false);
                        }
                    },1000);
                }
            }
        }

    }

}
